package model;

import java.io.Serializable;
import java.util.Comparator;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Transient;

import model.util.ModelException;

@Entity
public class Film extends ModelBase implements Serializable, Comparable<Film> {

	private static final long serialVersionUID = -2952735933715107252L;

	@Column
	private String name;
	private String hauptdarsteller;
	private String genre;
	private int laenge;

	@ManyToOne
	@JoinColumn(name = "datentraeger_id")
	private Datentraeger datentraeger;
	@Transient
	private int anzahl = 0;
	@Transient
	private Long datID = null;
	@Transient
	private FilmInfo info = new FilmInfo();

	public Film(Long id, String name, String hauptdarsteller, String genre,
			int laenge, Long datentraegerId) {
		setId(id);
		setName(name);
		setHauptdarsteller(hauptdarsteller);
		setGenre(genre);
		setLaenge(laenge);
		this.datID = datentraegerId;
		initFilmInfo();
	}

	public Film(Long id, String name, String hauptdarsteller, String genre,
			int laenge) {
		setId(id);
		setName(name);
		setHauptdarsteller(hauptdarsteller);
		setGenre(genre);
		setLaenge(laenge);
		initFilmInfo();
	}

	public Film(String name, String hauptdarsteller, String genre, int laenge) {
		setName(name);
		setHauptdarsteller(hauptdarsteller);
		setGenre(genre);
		setLaenge(laenge);
		initFilmInfo();

	}

	public Film(String name) {
		setName(name);
		initFilmInfo();

	}

	public int getAnzahl() {
		return anzahl;
	}

	public Film setDatentraegerId(Long datID) {
		if (datID == null)
			throw new ModelException("DatentraegerId must not be null!");
		this.datID = datID;
		return this;
	}

	public void setDatentraegerId(String datId) {
		try {
			setDatentraegerId(Long.parseLong(datId));
		} catch (NumberFormatException e) {
			throw new ModelException(
					"NumberFormatException at setDatentraegerId(String) in Produkt");
		}
	}

	public Long getDatentraegerID() {
		return datID;
	}

	public void setName(String name) {
		if (name == null || name.trim().length() == 0
				|| name.trim().length() > 20) {
			throw new IllegalArgumentException(
					"name must not be null, empty or longer than 20 characters!");
		}
		this.name = name.trim();
	}

	public String getName() {
		return name;
	}

	public void setHauptdarsteller(String hauptdarsteller) {
		if (hauptdarsteller == null || hauptdarsteller.trim().length() == 0
				|| hauptdarsteller.trim().length() > 30) {
			throw new IllegalArgumentException(
					"hauptdarsteller must not be null, empty or longer than 30 characters!");
		}
		this.hauptdarsteller = hauptdarsteller.trim();
	}

	public String getHauptdarsteller() {
		return hauptdarsteller;
	}

	public void setGenre(String genre) {
		if (genre == null || genre.trim().length() == 0
				|| genre.trim().length() > 30) {
			throw new IllegalArgumentException(
					"genre must not be null, empty or longer than 30 characters!");
		}
		this.genre = genre.trim();
	}

	public String getGenre() {
		return genre;
	}

	public void setLaenge(int laenge) {
		if (laenge <= 0 || laenge >= 500) {
			throw new IllegalArgumentException(
					"laenge must not be negative or zero!");
		}
		this.laenge = laenge;
	}

	public int getLaenge() {
		return laenge;
	}

	public void removeDatentraeger() {
		this.datID = null;
		info.setFilmDat("nicht zugeordnet");
	}

	public Film anzahlErhoehen(int anz) {
		if (anz < 0 || anz >= 1000000)
			throw new ModelException("anz has to be between 0 and 1000000!");
		if ((this.anzahl + anz) >= 1000000)
			throw new ModelException("anz storagecapacity overflow!");
		this.anzahl = this.anzahl + anz;
		return this;
	}

	public Film anzahlVermindern(int anz) {
		if (anz <= 0 || anz >= 1000000)
			throw new ModelException("anz has to be between 1 and 1000000!");
		if ((this.anzahl - anz) < 0)
			throw new ModelException("anz must not be greater than this.anz!");
		this.anzahl = this.anzahl - anz;
		return this;
	}

	public FilmInfo getInfo() {
		return info;
	}

	public Film setDatentraeger(Datentraeger datentraeger) {
		if (datentraeger == null) {
			throw new IllegalArgumentException("datentraeger must not be null");
		}
		this.datentraeger = datentraeger;
		return this;
	}

	@ManyToOne
	public Datentraeger getDatentraeger() {
		return datentraeger;
	}

	@Override
	public int compareTo(Film other) {
		return name.compareTo(other.getName());
	}

	private void initFilmInfo() {
		info.setFilmId("" + getId());
		info.setName(name);
		info.setHptDst(hauptdarsteller);
		info.setGenre(genre);
		info.setLaenge("" + laenge);
	}

	public void initDatInfo() {
		info.setFilmDat(datentraeger.getName());
	}

	public static final class HauptdarstellerNameComparator implements
			Comparator<Film> {

		@Override
		public int compare(Film left, Film right) {
			int result;
			if ((result = left.getHauptdarsteller().compareTo(
					right.getHauptdarsteller())) == 0) {
				result = left.getName().compareTo(right.getName());
			}
			return result;
		}

	}

	public static final class FilmNameComparator implements Comparator<Film> {

		@Override
		public int compare(Film left, Film right) {
			int result;
			if ((result = left.getName().compareTo(right.getName())) == 0) {
				result = left.getName().compareTo(right.getName());
			}
			return result;
		}

	}

	@Override
	public String toString() {
		return String.format(
				"%s {name=%s, hauptdarsteller=%s, genre=%s, laenge=%d}%n",
				getClass().getSimpleName(), name, hauptdarsteller, genre,
				laenge);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (name == null ? 0 : name.hashCode());
		result = prime * result
				+ (hauptdarsteller == null ? 0 : hauptdarsteller.hashCode());
		result = prime * result + (genre == null ? 0 : genre.hashCode());
		result = prime * result + laenge;
		return result;
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Film other = (Film) obj;
		if (anzahl != other.anzahl)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return super.equals(obj);
	}

	public class FilmInfo {
		private String filmId;
		private String name;
		private String hptDst;
		private String genre;
		private String laenge;
		private String filmDat = "nicht zugeordnet";

		/**
		 * @return
		 */
		public String getFilmId() {
			return filmId;
		}

		/**
		 * @param filmId
		 */
		public void setFilmId(String filmId) {
			this.filmId = filmId;
		}

		/**
		 * @return the name
		 */
		public String getName() {
			return name;
		}

		/**
		 * @param name
		 *            the name to set
		 */
		public void setName(String name) {
			this.name = name;
		}

		/**
		 * @return the hptDst
		 */
		public String getHptDst() {
			return hptDst;
		}

		/**
		 * @param hptDst
		 *            the hptDst to set
		 */
		public void setHptDst(String hptDst) {
			this.hptDst = hptDst;
		}

		/**
		 * @return the genre
		 */
		public String getGenre() {
			return genre;
		}

		/**
		 * @param genre
		 *            the genre to set
		 */
		public void setGenre(String genre) {
			this.genre = genre;
		}

		/**
		 * @return the laenge
		 */
		public String getLaenge() {
			return laenge;
		}

		/**
		 * @param laenge
		 *            the laenge to set
		 */
		public void setLaenge(String laenge) {
			this.laenge = laenge;
		}

		/**
		 * @return the filmDat
		 */
		public String getFilmDat() {
			return filmDat;
		}

		/**
		 * @param filmDat
		 *            the filmDat to set
		 */
		public void setFilmDat(String filmDat) {
			this.filmDat = filmDat;
		}

	}

}
